# -*-coding=utf-8 -*-
"""
    @author:sirius
    @time:2018.1.28
"""

import math
# 协同过滤算法
from random import choice, choices, random
from period.result import PeriodClassifier
from common.util import get_event_timestamp_list, format_time, get_event_list_by_period,\
     dicts_equal, get_apps_click_by_period, lol_contain_app

# 特征矩阵常量
P_MATRIX = [('workday', 'Morning'), ('workday', 'Noon'), ('workday', 'Afternoon'), ('workday', 'Evening'),
            ('workday', 'Night'), ('holiday', 'Morning'), ('holiday', 'Noon'), ('holiday', 'Afternoon'),
            ('holiday', 'Evening'), ('holiday', 'Night')]
# 应用列表常量
APPS_LIST = ['akncapserver', 'Messaging', 'Mail for Exchange', 'Standby mode', 'Telephone', 'screensaver',
             'MMFControllerProxyServer-1c52', 'Maps', 'Local-c837d0a8', 'File manager']

def similarityFuse(userList, itemList, feature_dict, relative_path):
     """
          基于条件概率的相似度融合框架
          US(x,y,x): user_event_list
          IS(x,y,x): itemList
          UIS(x,y,x): user_item_list
     """
     is_opened = 1
     user_event_list = []
     user_item_list = []
     normalized_events = []
     filename = relative_path + '/datasets/md_cache/app_sys_tmp.csv'
     item_file = relative_path + '/period/cache/ResultData.csv'
     if isinstance(itemList, str):
          userList, itemList = eval(userList), eval(itemList)
     else:
          userList = eval(userList)
     for user in userList:
          user_event_list.append(get_event_timestamp_list(filename, user[1]))
     for user_events in user_event_list:
          normalization_dict = {}
          for user_app in user_events:
               # 标准化
               if user_app[0] in normalization_dict.keys():
                    normalization_dict[user_app[0]] += math.log2(is_opened + 1) / len(user_events)
               else:
                    normalization_dict[user_app[0]] = math.log2(is_opened + 1) / len(user_events)

               for item in itemList:
                    if item[0] == user_app[0]:
                         user_item_list.append(user_app)

          normalized_events.append(normalization_dict)

     # 定义UIS数据集分子
     UIS_numerator = 0.0
     # 定义IS数据集条件概率
     ProbabilityUS = 0.0
     # 定义UIS数据集条件概率
     ProbabilityIS = 0.0
     # λ参数值
     lambda_para = 0.6
     # λ参数值
     delta_para = 0.4

     UIS = []
     usList = []
     isList = []
     uisList = []
     recommand_list = []

     # US数据集所有相似用户该时间区间关联性
     tz_USLen = 0
     # 获取IS数据集该时间区间应用的关联性
     tz_ISLen = 0
     # User-based统计应用启动次数字典
     start_num_dict = {}
     # Item-based统计应用启动次数字典
     click_num_dict = {}
     for user in userList:
          us_event_list = get_event_list_by_period(feature_dict, filename, user[1])
          # 获取US数据集相似用户该时间区间关联
          tz_USLen += len(us_event_list) * user[0]
          for us_app in us_event_list:
               if us_app in start_num_dict.keys():
                    start_num_dict[us_app] += 1 * user[0]
               else:
                    start_num_dict[us_app] = 1 * user[0]

     for item in itemList:
          it_event_list = get_apps_click_by_period(feature_dict, item_file, item[0])
          for item_app in it_event_list:
               # 获取IS数据集该时间区间应用的关联性
               tz_ISLen += item[1] * it_event_list[item_app]

               if item_app in click_num_dict.keys():
                    click_num_dict[item_app] += it_event_list[item_app] * item[1]
               else:
                    click_num_dict[item_app] = it_event_list[item_app] * item[1]

     for uis in user_item_list:
          global date_dict
          date_dict = {}
          date_dict = format_time(date_dict, uis[1])
          # 计算依赖UIS数据集条件概率
          if date_dict['period'] == feature_dict['period'] and date_dict['date'][5:] == feature_dict['date'][5:]:
               UIS_numerator += 1
     # 条件概率
     if len(user_item_list) == 0 or UIS_numerator == 0:
          ProbabilityUIS = 1
     else:
          ProbabilityUIS = float(UIS_numerator) / len(user_item_list)

     for uSimilarity in start_num_dict:
          usList.append([start_num_dict[uSimilarity]/tz_USLen, uSimilarity])
     for iSimilarity in click_num_dict:
          isList.append([click_num_dict[iSimilarity]/len(itemList), iSimilarity])
     for uiSimilarity in user_item_list:
          uisList.append([UIS_numerator/ProbabilityUIS, uiSimilarity[0]])

     for user in usList:
          for item in isList:
               for uis in uisList:
                    if user[1] == item[1] and user[1] == uis[1]:
                         # App启动条件概率列表
                         recommand_list.append([(uis[0] * lambda_para * delta_para + item[0] * delta_para * lambda_para
                                                 + user[0] * lambda_para * delta_para),
                                                uis[1]])
                    elif user[1] == item[1]:
                         recommand_list.append([(item[0] * delta_para * lambda_para + user[0] * lambda_para * delta_para), user[1]])
                         recommand_list.append([(uis[0] * lambda_para * delta_para), uis[1]])
                    elif user[1] == uis[1]:
                         recommand_list.append([(uis[0] * lambda_para * delta_para + user[0] * lambda_para * delta_para), uis[1]])
                         recommand_list.append([(item[0] * delta_para * lambda_para), item[1]])
                    elif item[1] == uis[1]:
                         recommand_list.append([(uis[0] * lambda_para * delta_para + item[0] * delta_para * lambda_para), uis[1]])
                         recommand_list.append([(user[0] * lambda_para * delta_para), user[1]])
                    else:
                         recommand_list.append([(uis[0] * lambda_para * delta_para), uis[1]])
                         recommand_list.append([(item[0] * delta_para * lambda_para), item[1]])
                         recommand_list.append([(user[0] * lambda_para * delta_para), user[1]])

     try:
          recommand_list.sort(reverse=True)
     except TypeError:
          for i in range(0, 5):
               recommand_list.append(choice(APPS_LIST))
     recommand_app_list = []
     for app_pro in recommand_list:
          if app_pro[1] not in recommand_app_list:
               recommand_app_list.append(app_pro[1])
          if len(recommand_app_list) >= 5:
               break
     return recommand_app_list


# 测试模型
def test_model():
     # 目标用户
     target_user = 5449.0
     # 命中率权重值
     weight = 7
     # 事件序列
     event_num = 0
     # 命中次数
     hitNum = 0
     # 周期律分类器
     p = PeriodClassifier()
     # 应用记录列表文件路径
     APP_SYS_PATH = './period/cache/ResultData.csv'
     MODEL_PATH = './period/cache/Rules.txt'
     # 获取事件列表
     EventList = list(get_event_timestamp_list(APP_SYS_PATH, target_user))
     # 上一个周期条件特征
     feature_last = {}

     # 读取User-based相似用户
     user_list_file = open('./user/cache/neighbors_tmp.txt', 'r')
     try:
          user_list = user_list_file.read()
     finally:
          user_list_file.close()
     # 读取User-based相似用户
     apps_obj = open('./period/cache/AppsResult.txt', 'r')
     try:
          apps_result = apps_obj.read()
     finally:
          apps_obj.close()

     index = 0
     apps_tmp = []
     date_dict_tmp = {}
     for event in EventList:
          global date_dict
          date_dict = {'location': event[2], 'speed': event[3]}
          date_dict = format_time(date_dict, event[1])

          if index == 0 or not dicts_equal(date_dict, feature_last):
               # 特定周期条件下，下一启动App
               last_app = ''
          else:
               last_app = EventList[index - 1][0]

          apps_list = p.get_result(date_dict, MODEL_PATH, last_app)

          while len(apps_list) < 5:
               if date_dict_tmp == date_dict:
                    apps_list = apps_tmp
               else:
                    app_random = [choices(APPS_LIST)[0], random()]
                    isNotContain, hitNum, event_num = lol_contain_app(apps_list, app_random)
                    if isNotContain:
                         continue
                    else:
                         apps_list.append(app_random)

          apps_tmp = apps_list
          date_dict_tmp = date_dict

          predictor_result = similarityFuse(user_list, apps_list, date_dict, '.')
          if len(predictor_result) > 0:
               print("-----------------------融合框架-----------------------")
               print("日期：" + date_dict['date'])
               print("星期：" + date_dict['week'])
               print("月份：" + date_dict['month'])
               print("时间：" + date_dict['period'])
               print(predictor_result)
               print("用户%s：%s" % (target_user, event[0]))
               print("----------------------------------------------------")

               if event[0] in [k for k in predictor_result]:
                    hitNum += 1
               event_num += 1
          index += 1
          feature_last = date_dict

     print("预测准确度：", float(hitNum) / event_num)


# 测试模型
def result_app(user_id, feature_dict, relative_header):
    # 周期律分类器
    p = PeriodClassifier()
    # 应用记录列表文件路径
    MODEL_PATH = relative_header + '/period/cache/Rules.txt'

    # 读取User-based相似用户
    user_list_file = open(relative_header + '/user/cache/neighbors_tmp.txt', 'r')
    try:
        user_list = user_list_file.read()
    finally:
        user_list_file.close()

    global date_dict
    date_dict = {'location': feature_dict['location'], 'speed': feature_dict['speed']}
    date_dict = format_time(date_dict, feature_dict['time'])
    p.get_result(date_dict, MODEL_PATH, last_app='')
    with open(relative_header + '/period/cache/AppsResult.txt') as apps_result_obj:
         apps_list = apps_result_obj.read()

    return similarityFuse(user_list, apps_list, date_dict, relative_header)


# 从这里开始运行
if __name__ == '__main__':
     test_model()
